﻿using Newtonsoft.Json;
using StructuredProgrammingAssignment.Linq;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace StructuredProgrammingAssignment.Helpers
{
	public class SPHelper
	{
		public static string GetSHA1HashData(string data) {
			//create new instance of SHA1
			SHA1 sha1 = SHA1.Create();

			//convert the input text to array of bytes
			byte[] hashData = sha1.ComputeHash(Encoding.Default.GetBytes(data));

			//create new instance of StringBuilder to save hashed data
			StringBuilder returnValue = new StringBuilder();

			//loop for each byte and add it to StringBuilder
			for (int i = 0; i < hashData.Length; i++) {
				returnValue.Append(hashData[i].ToString("x2"));
			}

			// return hexadecimal string
			return returnValue.ToString().ToUpper();
		}

		public static bool isValidEmail(string email) {
			string pattern = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|"
							+ @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)"
							+ @"@[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$";

			Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
			return regex.IsMatch(email);
		}

		// Serialize a UserAccount linq object into a json object
		public static Object JsonUserAccount(UserAccount account) {
			float trustRank = 0;
			foreach (Ranking r in account.Rankings) {
				trustRank += r.Rank ?? 0;
			}
			if (account.Rankings.Count > 0)
				trustRank = trustRank / account.Rankings.Count;

			var obj = new {
				Id = account.Id,
				Email = account.Email,
				FirstName = account.FirstName,
				LastName = account.LastName,
				TrustRank = trustRank,
				Properties = JsonConvert.DeserializeObject(account.Properties),
				CreatedDateTime = account.CreatedDateTime,
				ModifiedDateTime = account.ModifiedDateTime
			};

			return obj;
		}

		// Serialize a UserAccount linq object into a json object, hiding some sensitive properties
		public static Object JsonUserProfile(UserAccount account) {
			float trustRank = 0;
			foreach (Ranking r in account.Rankings) {
				trustRank += r.Rank ?? 0;
			}
			if (account.Rankings.Count > 0)
				trustRank = trustRank / account.Rankings.Count;

			var obj = new {
				Email = account.Email,
				FirstName = account.FirstName,
				LastName = account.LastName,
				TrustRank = trustRank,
				Properties = JsonConvert.DeserializeObject(account.Properties),
				CreatedDateTime = account.CreatedDateTime,
				ModifiedDateTime = account.ModifiedDateTime
			};

			return obj;
		}

		// Serialize a UserStuff linq object into a json object
		public static Object JsonUserStuff(UserStuff stuff) {
			var obj = new {
				Id = stuff.Id,
				UserEmail = stuff.UserAccount.Email,
				UserProfile = JsonUserProfile(stuff.UserAccount),
				Name = stuff.Name,
				Quantity = stuff.Quantity,
				Description = stuff.Description,
				CategoryId = stuff.CategoryId,
				Category = JsonCategory(stuff.Category),
				UnitPrice = stuff.UnitPrice,
				Status = stuff.Status,
				Properties = JsonConvert.DeserializeObject(stuff.Properties),
				CreatedDateTime = stuff.CreatedDateTime,
				ModifiedDateTime = stuff.ModifiedDateTime
			};

			return obj;
		}

		// Serialize a Category linq object into a json object
		public static Object JsonCategory(Category category) {
			var obj = new {
				Id = category.Id,
				ParentId = category.ParentId,
				Name = category.Name,
				Description = category.Description,
				Properties = JsonConvert.DeserializeObject(category.Properties),
				CreatedDateTime = category.CreatedDateTime,
				ModifiedDateTime = category.ModifiedDateTime
			};

			return obj;
		}

		// Serialize a Order linq object into a json object
		public static Object JsonOrder(Order order) {
			var obj = new {
				Id = order.Id,
				StuffId = order.StuffId,
				OrderUserEmail = order.UserAccount.Email,
				OrderUserProfile = JsonUserProfile(order.UserAccount),
				OwnerUserEmail = order.UserStuff.UserAccount.Email,
				OwnerUserProfile = JsonUserProfile(order.UserStuff.UserAccount),
				UserStuff = JsonUserStuff(order.UserStuff),
				Status = order.Status,
				OfferMoney = order.OfferMoney,
				PaymentType = order.PaymentType,
				Properties = JsonConvert.DeserializeObject(order.Properties),
				CreatedDateTime = order.CreatedDateTime,
				ModifiedDateTime = order.ModifiedDateTime
			};

			return obj;
		}

		// Handle properties field
		public static string ParseProperties(string properties, Dictionary<string, bool> propertyList, bool limitCustomProperties) {
			string value = properties ?? "{}";

			Dictionary<string, string> parsedValue = JsonConvert.DeserializeObject<Dictionary<string, string>>(value);

			// Remove redundant properties if limit setting set to true
			if (limitCustomProperties) {
				List<String> keysToRemove = new List<string>();

				foreach (string key in parsedValue.Keys) {
					if (!propertyList.ContainsKey(key)) {
						keysToRemove.Add(key);
					}
				}

				foreach (string key in keysToRemove) {
					parsedValue.Remove(key);
				}
			}

			foreach (string key in propertyList.Keys) {
				// if the property is required
				if (propertyList[key] && !parsedValue.ContainsKey(key)) {
					throw new Exception("Custom property [" + key + "] is required.");
				}
			}

			return JsonConvert.SerializeObject(parsedValue);
		}

	}
}